import os
import re
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import threading

class FileCounterApp:
    def __init__(self, root):
        self.root = root
        self.root.title("文件数量统计器")
        self.root.geometry("600x600")
        self.root.resizable(True, True)
        
        # 设置中文字体
        self.font = ('SimHei', 10)
        
        # 创建界面
        self.create_widgets()
        
        # 标志变量
        self.is_scanning = False
        self.stop_scan = False
        
        # 文件计数
        self.file_count = 0
    
    def create_widgets(self):
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="20")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 目录选择部分
        dir_frame = ttk.LabelFrame(main_frame, text="选择目录", padding="10")
        dir_frame.pack(fill=tk.X, pady=5)
        
        self.dir_var = tk.StringVar()
        dir_entry = ttk.Entry(dir_frame, textvariable=self.dir_var, width=50, font=self.font)
        dir_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
        
        browse_btn = ttk.Button(dir_frame, text="浏览...", command=self.browse_directory)
        browse_btn.pack(side=tk.RIGHT, padx=5)
        
        # 扩展名输入部分
        ext_frame = ttk.LabelFrame(main_frame, text="文件扩展名（支持通配符 *、?）", padding="10")
        ext_frame.pack(fill=tk.X, pady=5)
        
        self.ext_var = tk.StringVar(value="*")
        ext_entry = ttk.Entry(ext_frame, textvariable=self.ext_var, width=30, font=self.font)
        ext_entry.pack(side=tk.LEFT, padx=5)
        
        ttk.Label(ext_frame, text="例如: txt, mp3, doc?", font=self.font).pack(side=tk.LEFT, padx=5)
        
        # 递归搜索选项
        recursive_frame = ttk.Frame(main_frame)
        recursive_frame.pack(fill=tk.X, pady=5)
        
        self.recursive_var = tk.BooleanVar(value=True)
        recursive_check = ttk.Checkbutton(recursive_frame, text="包括子目录", variable=self.recursive_var)
        recursive_check.pack(side=tk.LEFT, padx=5)
        
        # 按钮部分
        btn_frame = ttk.Frame(main_frame)
        btn_frame.pack(fill=tk.X, pady=10)
        
        self.start_btn = ttk.Button(btn_frame, text="开始统计", command=self.start_scan)
        self.start_btn.pack(side=tk.LEFT, padx=5)
        
        self.stop_btn = ttk.Button(btn_frame, text="停止", command=self.stop_scanning, state=tk.DISABLED)
        self.stop_btn.pack(side=tk.LEFT, padx=5)
        
        # 结果显示部分
        result_frame = ttk.LabelFrame(main_frame, text="统计结果", padding="10")
        result_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 创建结果文本框
        self.result_text = tk.Text(result_frame, wrap=tk.WORD, font=self.font, height=10)
        self.result_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(self.result_text, command=self.result_text.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.result_text.config(yscrollcommand=scrollbar.set)
        
        # 进度条
        progress_frame = ttk.Frame(main_frame)
        progress_frame.pack(fill=tk.X, pady=5)
        
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(progress_frame, variable=self.progress_var, mode='indeterminate')
        self.progress_bar.pack(fill=tk.X, padx=5)
    
    def browse_directory(self):
        directory = filedialog.askdirectory(title="选择目录")
        if directory:
            self.dir_var.set(directory)
    
    def start_scan(self):
        # 获取目录和扩展名
        directory = self.dir_var.get().strip()
        extension_pattern = self.ext_var.get().strip()
        recursive = self.recursive_var.get()
        
        # 验证输入
        if not directory:
            messagebox.showerror("错误", "请选择要扫描的目录")
            return
        
        if not os.path.isdir(directory):
            messagebox.showerror("错误", f"目录不存在: {directory}")
            return
        
        if not extension_pattern:
            extension_pattern = ".*"
        
        # 禁用开始按钮，启用停止按钮
        self.start_btn.config(state=tk.DISABLED)
        self.stop_btn.config(state=tk.NORMAL)
        
        # 清空结果文本框
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(tk.END, f"开始扫描目录: {directory}\n")
        self.result_text.insert(tk.END, f"扩展名模式: {extension_pattern}\n")
        self.result_text.insert(tk.END, f"递归搜索: {'是' if recursive else '否'}\n")
        self.result_text.insert(tk.END, "=" * 50 + "\n")
        
        # 重置并开始进度条
        self.progress_var.set(0)  # 重置进度条位置
        self.progress_bar.stop()  # 先停止可能正在运行的进度条
        self.progress_bar.start(10)  # 降低延迟值使进度条更流畅
        
        # 初始化标志和计数
        self.is_scanning = True
        self.stop_scan = False
        self.file_count = 0
        
        # 在新线程中执行扫描
        self.scan_thread = threading.Thread(
            target=self.scan_files, 
            args=(directory, extension_pattern, recursive)
        )
        self.scan_thread.daemon = True
        self.scan_thread.start()
        
        # 检查线程是否完成
        self.root.after(100, self.check_scan_complete)
    
    def stop_scanning(self):
        self.stop_scan = True
        self.result_text.insert(tk.END, "扫描已停止...\n")
    
    def check_scan_complete(self):
        if not self.scan_thread.is_alive():
            self.is_scanning = False
            self.progress_bar.stop()
            self.start_btn.config(state=tk.NORMAL)
            self.stop_btn.config(state=tk.DISABLED)
            
            # 显示最终结果
            if not self.stop_scan:
                self.result_text.insert(tk.END, "\n扫描完成！\n")
                self.result_text.insert(tk.END, f"\n总计找到 {self.file_count} 个匹配的文件")
            else:
                self.result_text.insert(tk.END, f"\n已停止扫描，找到 {self.file_count} 个匹配的文件")
            
            # 滚动到底部
            self.result_text.see(tk.END)
        else:
            # 继续检查
            self.root.after(100, self.check_scan_complete)
    
    def wildcard_to_regex(self, pattern):
        # 将通配符转换为正则表达式（只支持 * 和 ?）
        regex = pattern
        # 转义特殊字符
        regex = re.escape(regex)
        # 转换通配符
        regex = regex.replace(r'\*', '.*')
        regex = regex.replace(r'\?', '.')
        # 确保匹配整个文件名（不只是部分）
        return f"^{regex}$"
    
    def scan_files(self, directory, extension_pattern, recursive):
        # 处理扩展名模式：简化为直接使用用户输入的模式
        if extension_pattern.strip() == ".*" or extension_pattern.strip() == "*":
            # 匹配所有文件的特殊情况
            regex = None
        else:
            try:
                # 将通配符转换为正则表达式
                pattern_to_use = self.wildcard_to_regex(extension_pattern)
                # 编译正则表达式
                regex = re.compile(pattern_to_use, re.IGNORECASE)
            except re.error:
                self.root.after(0, lambda: messagebox.showerror("错误", "无效的通配符模式"))
                return
        
        # 优化UI更新：批量更新结果
        batch_size = 100  # 增加批量大小，减少UI更新频率
        found_files = []
        last_update_time = 0  # 上次更新UI的时间戳（用于处理少量文件）
        
        try:
            # 预计算总文件数的估计值（用于更智能的UI更新）
            total_files_estimate = 0
            if recursive:
                for root, _, files in os.walk(directory):
                    total_files_estimate += len(files)
            else:
                total_files_estimate = len([f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))])
            
            # 根据估计的文件总数动态调整批处理大小
            if total_files_estimate > 1000:
                batch_size = 200
            elif total_files_estimate < 100:
                batch_size = 20
            
            if recursive:
                # 递归扫描所有子目录
                for root_dir, _, files in os.walk(directory):
                    if self.stop_scan:
                        break
                    
                    # 批量处理文件，减少循环内的条件检查
                    matched_files = []
                    for file in files:
                        # 获取扩展名（去掉点号）
                        _, ext = os.path.splitext(file)
                        ext = ext[1:]  # 去掉点号
                        
                        # 检查匹配
                        match = False
                        if regex is None:
                            # 匹配所有文件
                            match = True
                        elif ext == "":
                            # 空扩展名，不匹配非*模式
                            match = False
                        else:
                            # 直接使用正则匹配扩展名
                            match = regex.match(ext)
                        
                        if match:
                            full_path = os.path.join(root_dir, file)
                            matched_files.append(full_path)
                    
                    # 批量更新计数和结果列表
                    if matched_files:
                        self.file_count += len(matched_files)
                        found_files.extend(matched_files)
                        
                        # 获取当前时间
                        current_time = os.times()[4]  # 使用进程时间作为简单的时间戳
                        
                        # 批量更新UI或如果找到少量文件也及时更新
                        if len(found_files) >= batch_size or (current_time - last_update_time > 0.3 and found_files):
                            self._update_ui_batch(found_files)
                            found_files = []
                            last_update_time = current_time
                            
                        # 检查是否需要停止
                        if self.stop_scan:
                            break
            else:
                # 仅扫描当前目录
                if self.stop_scan:
                    return
                
                # 批量处理文件
                matched_files = []
                for item in os.listdir(directory):
                    if self.stop_scan:
                        break
                    
                    full_path = os.path.join(directory, item)
                    if os.path.isfile(full_path):
                        # 获取扩展名（去掉点号）
                        _, ext = os.path.splitext(item)
                        ext = ext[1:]  # 去掉点号
                        
                        # 检查匹配
                        match = False
                        if regex is None:
                            # 匹配所有文件
                            match = True
                        elif ext == "":
                            # 空扩展名，不匹配非*模式
                            match = False
                        else:
                            # 直接使用正则匹配扩展名
                            match = regex.match(ext)
                        
                        if match:
                            matched_files.append(full_path)
                
                # 批量更新
                if matched_files:
                    self.file_count += len(matched_files)
                    found_files.extend(matched_files)
                    self._update_ui_batch(found_files)
            
            # 更新剩余的文件列表
            if found_files and not self.stop_scan:
                self._update_ui_batch(found_files)
                
        except Exception as e:
            self.root.after(0, lambda: messagebox.showerror("错误", f"扫描过程中发生错误: {str(e)}"))
    
    def _update_ui_batch(self, file_paths):
        """批量更新UI，减少UI更新频率，优化进度条流畅度"""
        def update_text():
            # 使用单行文本插入代替多行，提高效率
            text_content = "\n".join([f"找到: {path}" for path in file_paths])
            self.result_text.insert(tk.END, text_content + "\n")
            # 只滚动一次到底部
            self.result_text.see(tk.END)
        
        # 在UI线程中执行更新，使用较短的延迟确保响应性
        self.root.after_idle(update_text)

if __name__ == "__main__":
    root = tk.Tk()
    app = FileCounterApp(root)
    root.mainloop()